package top.v5it.japi.plus.core.spring.web.interceptor;

import cn.hutool.core.util.IdUtil;
import com.fasterxml.jackson.databind.JsonNode;
import top.v5it.japi.plus.common.context.Authorized;
import top.v5it.japi.plus.common.context.AuthorizedContextHolder;
import top.v5it.japi.plus.common.func.Func1;
import top.v5it.japi.plus.common.func.MethodTemplate;
import top.v5it.japi.plus.common.tuple.Tuple3;
import top.v5it.japi.plus.common.tuple.Tuple5;
import top.v5it.japi.plus.common.tuple.Tuples;
import top.v5it.japi.plus.common.util.JackSonUtil;
import top.v5it.japi.plus.core.api.Result;
import top.v5it.japi.plus.core.spring.web.JapiEada;
import top.v5it.japi.plus.core.spring.web.JapiEadaUtil;

import java.time.Instant;
import java.util.Optional;

/**
 * 响应结果包装
 *
 * @author zhanpu
 * @date 2022/6/10
 */
public interface JapiResponseWrapper {

    /**
     * 响应头信息
     *
     * @return {@link Tuple5 <Long, String, String, String, String>}
     */
    default Tuple5<Long, String, String, String, String> require() {
        Authorized authorized = AuthorizedContextHolder.getRequestAuthAttributes();
        authorized = Optional.ofNullable(authorized).orElseGet(Authorized::new);
        return Tuples.of(Instant.now().getEpochSecond(), IdUtil.fastSimpleUUID(), authorized.getRequestId(), authorized.getServerSerialNo(), authorized.getChannel());
    }

    /**
     * 构建待签名字符
     * <pre>
     *     时间戳\n
     *     随机字符\n
     *     消息体\n
     * </pre>
     *
     * @param timestamp 时间戳
     * @param nonceStr  随机字符
     * @param body      消息体
     * @return 构建后的待签名字符
     */
    default String buildMessage(final long timestamp, final String nonceStr, final String body) {
        return timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }

    /**
     * 响应结果包装，包括签名值计算，响应结果格式重置
     *
     * @param body 响应报文体
     * @return 响应实体
     */
    Result wrapper(Object body);

    /**
     * 成功，有实体信息
     *
     * @param body   响应体
     * @param mapper {@link Tuple3 <Boolean, JapiEada, Func1<String, String, RuntimeException>>}
     * @return 包装后的响应结果
     */
    default Result wrapper(Object body, Tuple3<Boolean, JapiEada, Func1<String, String, RuntimeException>> mapper) {
        JsonNode jsonNode =
                MethodTemplate.executeWithException(() -> JackSonUtil.getMapper().convertValue(body, JsonNode.class)
                        , () -> new IllegalArgumentException("响应报文体格式错误"));

        JsonNode newJsonNode =
                Optional.ofNullable(mapper.getTwo())
                        .filter(JapiEada::isEncrypt)
                        .filter(v -> JapiEada.Type.ENCRYPT.equals(v.type()))
                        .map(v -> JapiEadaUtil.findResourceApply(jsonNode, mapper))
                        .orElse(jsonNode);

        return wrapper(newJsonNode);
    }
}
